#ifndef SquirrelBindingsUtils_h
#define SquirrelBindingsUtils_h

struct ScriptClassMemberDecl  {
	const SQChar *name;
	SQFUNCTION func;
	int params;
	const SQChar *typemask;
};

struct SquirrelClassDecl  {
	const SQChar *name;
	const SQChar *base;
	const ScriptClassMemberDecl *members;
};

struct ScriptConstantDecl  {
	const SQChar *name;
	SQObjectType type;
	union value {
		value(float v){ f = v; }
		value(int v){ i = v; }
		value(const SQChar *v){ s = v; }
		float f;
		int i;
		const SQChar *s;
	}val;
};

struct ScriptNamespaceDecl  {
	const SQChar *name;
	const ScriptClassMemberDecl *members;
	const ScriptConstantDecl *constants;
	const ScriptClassMemberDecl *delegate;	
};

bool CreateClass(HSQUIRRELVM v,SquirrelClassDecl *cd)
{
	int n = 0;
	int oldtop = sq_gettop(v);
	sq_pushroottable(v);
	sq_pushstring(v,cd->name,-1);
	if(cd->base) {
		sq_pushstring(v,cd->base,-1);
		if(SQ_FAILED(sq_get(v,-3))) {
			sq_settop(v,oldtop);
			return false;
		}
	}
	if(SQ_FAILED(sq_newclass(v,cd->base?1:0))) {
		sq_settop(v,oldtop);
		return false;
	}
	sq_settypetag(v,-1,cd);
	const ScriptClassMemberDecl *members = cd->members;
	const ScriptClassMemberDecl *m = NULL;
	while(members[n].name) {
		m = &members[n];
		sq_pushstring(v,m->name,-1);
		sq_newclosure(v,m->func,0);
		sq_setparamscheck(v,m->params,m->typemask);
		sq_setnativeclosurename(v,-1,m->name);
		sq_createslot(v,-3);
		n++;
	}
	sq_createslot(v,-3);
	sq_pop(v,1);
	return true;
}

#define BOOL bool
#define FALSE false
#define TRUE true
#define _T 



BOOL CreateNativeClassInstance(HSQUIRRELVM v,const SQChar *classname,SQUserPointer ud,SQRELEASEHOOK hook)
{
	int oldtop = sq_gettop(v);
	sq_pushroottable(v);
	sq_pushstring(v,classname,-1);
	if(SQ_FAILED(sq_rawget(v,-2))){
		sq_settop(v,oldtop);
		return FALSE;
	}
	//sq_pushroottable(v);
	if(SQ_FAILED(sq_createinstance(v,-1))) {
		sq_settop(v,oldtop);
		return FALSE;
	}
	sq_remove(v,-3); //removes the root table
	sq_remove(v,-2); //removes the the class
	if(SQ_FAILED(sq_setinstanceup(v,-1,ud))) {
		sq_settop(v,oldtop);
		return FALSE;
	}
	sq_setreleasehook(v,-1,hook);
	return TRUE;
}



#define _BEGIN_CLASS(classname)  \
		int __##classname##__typeof(HSQUIRRELVM v) \
		{ \
			sq_pushstring(v,(#classname),-1); \
			return 1; \
		} \
		struct ScriptClassMemberDecl __##classname##_members[] = { \
		{("_typeof"),__##classname##__typeof,1,NULL},

#define _BEGIN_NAMESPACE(xnamespace) struct ScriptClassMemberDecl __##xnamespace##_members[] = { 
#define _BEGIN_NAMESPACE_CONSTANTS(xnamespace) {NULL,NULL,NULL,NULL}}; \
	struct ScriptConstantDecl __##xnamespace##_constants[] = { 

#define _BEGIN_DELEGATE(xnamespace) struct ScriptClassMemberDecl __##xnamespace##_delegate[] = { 
#define _DELEGATE(xnamespace) __##xnamespace##_delegate
#define _END_DELEGATE(classname) {NULL,NULL,NULL,NULL}};

#define _CONSTANT(name,type,val) {_T(#name),type,val},
#define _CONSTANT_IMPL(name,type) {_T(#name),type,name},

#define _MEMBER_FUNCTION(classname,name,nparams,typemask) \
	{(#name),__##classname##_##name,nparams,typemask},

#define _END_NAMESPACE(classname,delegate) {NULL,OT_NULL,0}}; \
struct ScriptNamespaceDecl __##classname##_decl = {   \
	_T(#classname), __##classname##_members,__##classname##_constants,delegate };

#define _END_CLASS(classname) {NULL,NULL,NULL,NULL}}; \
struct SquirrelClassDecl __##classname##_decl = {  \
	(#classname), NULL, __##classname##_members }; 
	

#define _END_CLASS_INHERITANCE(classname,base) {NULL,NULL,NULL,NULL}}; \
struct SquirrelClassDecl __##classname##_decl = {  \
	_T(#classname), _T(#base), __##classname##_members };

#define _MEMBER_FUNCTION_IMPL(classname,name) \
	int __##classname##_##name(HSQUIRRELVM v)

#define _INIT_STATIC_NAMESPACE(classname) CreateStaticNamespace(SquirrelVM::GetVMPtr(),&__##classname##_decl);
#define _INIT_CLASS(VM,classname) CreateClass(VM,&__##classname##_decl);

#define _DECL_STATIC_NAMESPACE(xnamespace) extern struct ScriptNamespaceDecl __##xnamespace##_decl;
#define _DECL_CLASS(classname) extern struct SquirrelClassDecl __##classname##_decl;

#define _CHECK_SELF(cppclass,scriptclass) \
	cppclass *self = NULL; \
	if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,&__##scriptclass##_decl))) { \
		return sq_throwerror(v,_T("invalid instance type"));\
	}

#define _CHECK_INST_PARAM(pname,idx,cppclass,scriptclass)  \
	cppclass *pname = NULL; \
	if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer*)&pname,&__##scriptclass##_decl))) { \
		return sq_throwerror(v,_T("invalid instance type"));\
	} \

#define _CHECK_INST_PARAM_BREAK(pname,idx,cppclass,scriptclass)  \
	cppclass *pname = NULL; \
	if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer*)&pname,(unsigned int)&__##scriptclass##_decl))) { \
		break; \
	} \

#define _CLASS_TAG(classname) ((unsigned int)&__##classname##_decl)


#define _DECL_NATIVE_CONSTRUCTION(classname,cppclass) \
	BOOL push_##classname(cppclass &quat); \
	SquirrelObject new_##classname(cppclass &quat);

#define _IMPL_NATIVE_CONSTRUCTION(classname,cppclass) \
static int classname##_release_hook(SQUserPointer p, int size) \
{ \
	if(p) { \
		cppclass *pv = (cppclass *)p; \
		delete pv; \
	} \
	return 0; \
} \
bool push_##classname(HSQUIRRELVM v,cppclass &quat) \
{ \
	cppclass *newquat = new cppclass; \
	*newquat = quat; \
	if(!CreateNativeClassInstance(v,(#classname),newquat,classname##_release_hook)) { \
		delete newquat; \
		return FALSE; \
	} \
	return TRUE; \
} \
HSQOBJECT new_##classname(HSQUIRRELVM v,cppclass &quat) \
{ \
	HSQOBJECT ret; \
	if(push_##classname(v, quat)) { \
		sq_getstackobj(v,-1,&ret);\
		sq_addref(v,&ret);\
		sq_pop(v,1); \
	} \
	return ret; \
} \
int construct_##classname(HSQUIRRELVM v,cppclass *p) \
{ \
	sq_setinstanceup(v,1,p); \
	sq_setreleasehook(v,1,classname##_release_hook); \
	return 1; \
}



#define _DECLARE_REFCOUNTED_NEW(cppclass,classname) \
	SquirrelObject new_##classname(cppclass *ptr) { \
		if(CreateRefCountedInstance(SquirrelVM::GetVMPtr(),_T(#classname),ptr)) { \
			HSQOBJECT o; \
			sq_getstackobj(SquirrelVM::GetVMPtr(),-1,&o); \
			SquirrelObject tmp = o; \
			sq_pop(SquirrelVM::GetVMPtr(),1); \
			return tmp; \
		} \
		return SquirrelObject() ; \
	}

#define _RETURN_REFCOUNTED_INSTANCE(classname,ptr) \
	if(!CreateRefCountedInstance(SquirrelVM::GetVMPtr(),_T(#classname),ptr)) { \
		return sa.ThrowError(_T("cannot create the class instance")); \
	} \
	return 1;

#endif

// BOOL CreateStaticClass(HSQUIRRELVM v,SquirrelClassDecl *cd);
// BOOL CreateStaticNamespace(HSQUIRRELVM v,ScriptNamespaceDecl *sn);
//BOOL CreateClass(HSQUIRRELVM v,SquirrelClassDecl *cd);
//BOOL InitScriptClasses(HSQUIRRELVM v);
//BOOL CreateNativeClassInstance(HSQUIRRELVM v,const SQChar *classname,SQUserPointer ud,SQRELEASEHOOK hook);
//BOOL CreateRefCountedInstance(HSQUIRRELVM v,const SQChar *classname,IUnknown *pRC);
//BOOL CreateRefCountedInstanceChached(HSQUIRRELVM v,const SQChar *classname,IUnknown *pRC);
//int refcounted_release_hook(SQUserPointer p, int size);
//int construct_RefCounted(IUnknown *p);